/**
 * 
 */
package org.wolf.core.schema;

import java.util.Date;

import org.apache.lucene.analysis.NumericTokenStream;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.NumericRangeQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.SortField;
import org.apache.lucene.util.NumericUtils;
import org.wolf.core.util.DateUtil;

/**
 * @author 何小锋
 * 
 */
public class DateField extends FieldType {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private int precisionStep = 8;

	public int getPrecisionStep() {
		if (precisionStep <= 0 || precisionStep >= 64)
			precisionStep = Integer.MAX_VALUE;
		return precisionStep;
	}

	public void setPrecisionStep(int precisionStep) {
		this.precisionStep = precisionStep;
	}

	@Override
	public boolean isTokenized() {
		return true;
	}

	@Override
	public void setSortMissingFirst(boolean sortMissingFirst) {
	}

	@Override
	public void setSortMissingLast(boolean sortMissingLast) {
	}

	@Override
	public String toInternal(Object value) {
		long val;
		if (value instanceof Date) {
			val = ((Date) value).getTime();
		} else
			val = DateUtil.parse(value.toString()).getTime();
		return NumericUtils.longToPrefixCoded(val);
	}

	@Override
	public Object toExternal(Fieldable f) {
		byte[] arr = f.getBinaryValue();
		if (arr == null)
			return "ERROR:TYPE-MISMATCH" + f.stringValue();
		int high = (arr[0] << 24) | ((arr[1] & 0xff) << 16)
				| ((arr[2] & 0xff) << 8) | (arr[3] & 0xff);
		int low = (arr[4] << 24) | ((arr[5] & 0xff) << 16)
				| ((arr[6] & 0xff) << 8) | (arr[7] & 0xff);
		long value = (((long) high) << 32) | (low & 0x0ffffffffL);
		return new Date(value);
	}

	@Override
	public Field createField(DocField field, Object value, float boost) {
		if (value == null || !field.isIndexed() && !field.isStored()) {
			return null;
		}
		long val;
		if (value instanceof Date) {
			val = ((Date) value).getTime();
		} else
			val = DateUtil.parse(value.toString()).getTime();

		Field result;
		TokenStream ts = null;
		if (field.isIndexed()) {
			ts = new NumericTokenStream(getPrecisionStep()).setLongValue(val);
		}
		if (field.isStored()) {
			byte[] arr = new byte[8];
			arr[0] = (byte) (val >>> 56);
			arr[1] = (byte) (val >>> 48);
			arr[2] = (byte) (val >>> 40);
			arr[3] = (byte) (val >>> 32);
			arr[4] = (byte) (val >>> 24);
			arr[5] = (byte) (val >>> 16);
			arr[6] = (byte) (val >>> 8);
			arr[7] = (byte) (val);
			result = new Field(field.getName(), arr);
			if (ts != null)
				result.setTokenStream(ts);
		} else {
			result = new Field(field.getName(), ts);
		}

		result.setOmitNorms(field.isOmitNorms());
		result.setOmitTermFreqAndPositions(field.isOmitTf());
		result.setBoost(boost);
		return result;
	}

	@Override
	protected SortField createSortField(DocField field, boolean reverse) {
		return new SortField(field.getName(),
				FieldCache.NUMERIC_UTILS_LONG_PARSER, reverse);
	}

	@Override
	public Query getRangeQuery(QueryParser parser, DocField field, String min,
			String max, boolean minInclusive, boolean maxInclusive) {
		return NumericRangeQuery.newLongRange(field.getName(),
				getPrecisionStep(), min == null ? null : DateUtil.parse(min)
						.getTime(), max == null ? null : DateUtil.parse(max)
						.getTime(), minInclusive, maxInclusive);
	}

}
